<html>
    <head>
        <title>创建后台任务</title>
    </head>
    <body>
        <script>
             /*
                        二、创建后台任务

                                后台任务应该间接或者直接的实现 IBackgroundWorker接口。

                                后天任务本质上是单例的(Singleton). 因此，你的后台任务类只有一个实例被实例化并运行。


                                1、BackgroundWorkerBase 基类

                                     派生自BackgroundWorkerBase基类，是创建后台任务的简单方法。
                                     
                                        // 继承自 BackgroundWorkerBase 基类，是实现后台任务的最简单方法。
                                        public class MyWorker : BackgroundWorkerBase
                                        {
                                            // 重写StartAsync 启动后台任务
                                            public override Task StartAsync(CancellationToken cancellationToken = default)
                                            {
                                                // 启动时候要做的事情
                                            }

                                            // 重写 StopAsync 停止后台任务
                                            public override Task StopAsync(CancellationToken cancellationToken = default)
                                            {
                                                // 停止时候要做的事情
                                            }
                                        }

                                        你可以直接实现IBackgroundWorker，但是BackgroundWorkerBase提供了一些有用的属性，如Logger。


                                2、 AysncPeriodicBackgroundWorkerBase （异步间歇性后台任务基类）
                                
                                        假如如果一个用户30天内没有登录，我们想激活用户活性。

                                        AsyncPeriodicBackgroundWorkerBase类简化了创建周期性后台任务的过程：

                                            // 声明周期性后台任务类
                                            public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase // 周期性后台任务基类
                                            {
                                                // 构造函数
                                                public PassiveUserCheckerWorker(
                                                        AbpAsyncTimer timer, // 异步计时器
                                                        IServiceScopeFactory serviceScopeFactory // 服务作用域工厂
                                                    ) : base(timer, serviceScopeFactory)
                                                {
                                                    Timer.Period = 600000; //10 分钟
                                                }

                                                // 重写 DoWorkAsync 方法，执行后台任务
                                                protected async override Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
                                                {
                                                    Logger.LogInformation("Starting: Setting status of inactive users...");

                                                    //使用服务注入（不从构造函数中注入服务，因为使用了IServiceScope）
                                                    var userRepository = workerContext.ServiceProvider
                                                                                      .GetRequiredService<IUserRepository>();

                                                    // 执行后台任务逻辑
                                                    await userRepository.UpdateInactiveUserStatusesAsync();

                                                    Logger.LogInformation("Completed: Setting status of inactive users...");
                                                }
                                            }
                                                 
                                       ①、AsyncPeriodicBackgroundWorkerBase使用AbpAsyncTimer（一个线程安全计时器）对象来确定周期。 
                                          我们可以在构造函数中设置它的Period属性。

                                       ②、它需要实现DoWorkAsync方法来执行周期性工作。

                                       ③、从PeriodicBackgroundWorkerContext而不是构造函数注入解决依赖关系是一种很好的做法。
                                          因为AsyncPeriodicBackgroundWorkerBase使用IServiceScope，当你的工作完成时，已释放。

                                       ④、AsyncPeriodicBackgroundWorkerBase捕获并记录由DoWorkAsync方法抛出的异常。
                    */
        </script>
    </body>
</html>